﻿using System;
using System.Collections.Generic;
using BlueDot.Data.Core;
using Microsoft.Synchronization.Data;

namespace Syncronization.Utils
{
    public static class SyncSchemaUtils
    {
        #region public

        /// <summary>
        /// Configures the columns.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="table">The table.</param>
        /// <param name="primaryKeys">The primary keys.</param>
        public static void ConfigureColumns(ISchemaBuilder builder, SyncSchemaTable table, List<string> primaryKeys)
        {
            builder.Columns.Each(item =>
                                     {
                                         DataStoreColumnSchema column = item.Value;

                                         SyncSchemaColumn newColumn = table.Columns.Add(column.Name);
                                         newColumn.AutoIncrement = column.IsGeneratedByDataStore;
                                         newColumn.AllowNull = !column.IsRequired;

                                         if (IsNullableType(column.ClrDataType))
                                             newColumn.DataType = GetPrimitiveType(column.ClrDataType);
                                         else
                                             newColumn.DataType = column.ClrDataType;

                                         if (column.MaxLength.HasValue && column.MaxLength != 0)
                                             newColumn.MaxLength = column.MaxLength.Value;

                                         if (column.IsUniqueKey)
                                             primaryKeys.Add(column.Name);
                                     });

            var entityBuilder = builder as EntityBuilder;
            if (entityBuilder != null)
            {
                if (EntityUtils.IsEntityType(entityBuilder.BaseEntityType))
                {
                    EntityBuilder baseBuilder = EntityMap.GetEntityBuilder(entityBuilder.BaseEntityType);
                    if (baseBuilder != null)
                        ConfigureColumns(baseBuilder, table, primaryKeys);
                }
            }
        }

        /// <summary>
        /// Creates the sync schem table.
        /// </summary>
        /// <param name="schemaBuilder">The schema builder.</param>
        /// <param name="schema">The schema.</param>
        /// <returns></returns>
        public static SyncSchemaTable CreateSyncSchemTable(ISchemaBuilder schemaBuilder, SyncSchema schema)
        {
            if (schema.Tables.Contains(schemaBuilder.Name))
                return null;

            SyncSchemaTable table = schema.Tables.Add(schemaBuilder.Name);

            var primaryKeys = new List<string>();

            ConfigureColumns(schemaBuilder, table, primaryKeys);

            table.PrimaryKey = primaryKeys.ToArray();

            return table;
        }

        /// <summary>
        /// Determines whether [is nullable type] [the specified property type].
        /// </summary>
        /// <param name="propertyType">Type of the property.</param>
        /// <returns>
        /// 	<c>true</c> if [is nullable type] [the specified property type]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsNullableType(Type propertyType)
        {
            return (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof (Nullable<>));
        }

        #endregion

        #region private

        private static Type GetPrimitiveType(Type type)
        {
            if (type.GetGenericArguments().Length > 0)
            {
                return type.GetGenericArguments()[0];
            }
            return type;
        }

        #endregion
    }
}